/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#ifndef __M2_H__
#define __M2_H__

#include "GPrerequisites.h"

#define M2_MAX_MODEL_TEXTURE	32

#define	RENDERFLAGS_UNLIT	1
#define	RENDERFLAGS_UNFOGGED	2
#define	RENDERFLAGS_TWOSIDED	4
#define	RENDERFLAGS_BILLBOARD	8
#define	RENDERFLAGS_ZBUFFERED	16

#define	TEXTURE_WRAPX 1
#define TEXTURE_WRAPY 2

#define	TEXTUREUNIT_STATIC	16

#define	MAX_ANIMATED	500

#define INTERPOLATION_NONE 0
#define INTERPOLATION_LINEAR 1
#define INTERPOLATION_HERMITE 2
#define INTERPOLATION_BEZIER 3


#define	ANIM_STAND	0


#define	ANIMATION_HANDSCLOSED	15
#define	ANIMATION_MOUNT			91
#define	ANIMATION_LOOPED		0x20 // flags

#define	MODELBONE_BILLBOARD	8
#define	MODELBONE_TRANSFORM	512

namespace GNgine
{
	enum M2KeyBoneTable 
	{
		BONE_LARM = 0,		// 0, ArmL: Left upper arm
		BONE_RARM,			// 1, ArmR: Right upper arm
		BONE_LSHOULDER,		// 2, ShoulderL: Left Shoulder / deltoid area
		BONE_RSHOULDER,		// 3, ShoulderR: Right Shoulder / deltoid area
		BONE_STOMACH,		// 4, SpineLow: (upper?) abdomen
		BONE_WAIST,			// 5, Waist: (lower abdomen?) waist
		BONE_HEAD,			// 6, Head
		BONE_JAW,			// 7, Jaw: jaw/mouth
		BONE_RFINGER1,		// 8, IndexFingerR: (Trolls have 3 "fingers", this points to the 2nd one.
		BONE_RFINGER2,		// 9, MiddleFingerR: center finger - only used by dwarfs.. don't know why
		BONE_RFINGER3,		// 10, PinkyFingerR: (Trolls have 3 "fingers", this points to the 3rd one.
		BONE_RFINGERS,		// 11, RingFingerR: Right fingers -- this is -1 for trolls, they have no fingers, only the 3 thumb like thingys
		BONE_RTHUMB,		// 12, ThumbR: Right Thumb
		BONE_LFINGER1,		// 13, IndexFingerL: (Trolls have 3 "fingers", this points to the 2nd one.
		BONE_LFINGER2,		// 14, MiddleFingerL: Center finger - only used by dwarfs.
		BONE_LFINGER3,		// 15, PinkyFingerL: (Trolls have 3 "fingers", this points to the 3rd one.
		BONE_LFINGERS,		// 16, RingFingerL: Left fingers
		BONE_LTHUMB,		// 17, ThubbL: Left Thumb
		BONE_BTH,			// 18, $BTH: In front of head
		BONE_CSR,			// 19, $CSR: Left hand
		BONE_CSL,			// 20, $CSL: Left hand
		BONE_BREATH,		// 21, _Breath
		BONE_NAME,			// 22, _Name
		BONE_NAMEMOUNT,		// 23, _NameMount
		BONE_CHD,			// 24, $CHD: Head
		BONE_CCH,			// 25, $CCH: Bust
		BONE_ROOT,			// 26, Root: The "Root" bone,  this controls rotations, transformations, etc of the whole model and all subsequent bones.
		BONE_WHEEL1,		// 27, Wheel1
		BONE_WHEEL2,		// 28, Wheel2
		BONE_WHEEL3,		// 29, Wheel3
		BONE_WHEEL4,		// 30, Wheel4
		BONE_WHEEL5,		// 31, Wheel5
		BONE_WHEEL6,		// 32, Wheel6
		BONE_WHEEL7,		// 33, Wheel7
		BONE_WHEEL8,		// 34, Wheel8
		BONE_MAX
	};

	enum M2TextureTypes
	{
		TEXTURE_FILENAME=0,			// Texture given in filename
		TEXTURE_BODY,				// Body + clothes
		TEXTURE_CAPE,				// Item, Capes ("Item\ObjectComponents\Cape\*.blp")
		TEXTURE_ARMORREFLECT,		// 
		TEXTURE_HAIR=6,				// Hair, bear
		TEXTURE_FUR=8,				// Tauren fur
		TEXTURE_INVENTORY_ART1,		// Used on inventory art M2s (1): inventoryartgeometry.m2 and inventoryartgeometryold.m2
		TEXTURE_QUILL,				// Only used in quillboarpinata.m2. I can't even find something referencing that file. Oo Is it used?
		TEXTURE_GAMEOBJECT1,		// Skin for creatures or gameobjects #1
		TEXTURE_GAMEOBJECT2,		// Skin for creatures or gameobjects #2
		TEXTURE_GAMEOBJECT3,		// Skin for creatures or gameobjects #3
		TEXTURE_INVENTORY_ART2		// Used on inventory art M2s (2): ui-buffon.m2 and forcedbackpackitem.m2 (LUA::Model:ReplaceIconTexture("texture"))
	};

	enum M2BlendModes 
	{
		BM_OPAQUE,
		BM_TRANSPARENT,
		BM_ALPHA_BLEND,
		BM_ADDITIVE,
		BM_ADDITIVE_ALPHA,
		BM_MODULATE,
		BM_MODULATEX2
	};

	class M2Header
	{
	public:
		char id[4];					//"MD20"
		unsigned char version[4];		// 8 1 0 0 = WoW 3.0 models	// 4 1 0 0 = WoW 2.0 models //0 1 0 0 = WoW 1.0 models

		unsigned int nameLen;	//length of the model's name
		unsigned int nameOffset;	//offset to the name
		unsigned int globalFlags;	//1: tilt x, 2: tilt y, 4:, 8: add another field in header

		unsigned int nGlobSeqs; //glob sequence count?
		unsigned int globSeqOffset; //a list of timestamps.

		unsigned int nAnims;				//0x01C	unsigned int	nAnimations
		unsigned int animsOffset;			// Information about the animations in the model.

		unsigned int nAnimLookup; // AnimationRelated
		unsigned int animLookupOffset; // Mapping of global IDs to the entries in the Animation sequences block.

		unsigned int nBones; // BonesAndLookups
		unsigned int bonesOffset; // Information about the bones in this model.
		unsigned int nKeyBoneLookup; // BonesAndLookups
		unsigned int keyBoneLookupOffset; // Lookup table for key skeletal bones.

		unsigned int nVertices; // 
		unsigned int verticesOffset; // Vertices of the model.
		unsigned int nViews; // Views (LOD) are now in .skins.

		unsigned int nColors; //
		unsigned int colorsOffset; // Color definitions.

		unsigned int nTex; // 
		unsigned int texOffset; // Textures of this model.

		unsigned int nTransps; //
		unsigned int transpOffset; // Transparency of textures.

		unsigned int nTexAnims;	//
		unsigned int texAnimsOffset;
		unsigned int nTexReplace; 
		unsigned int texReplaceOffset; // Replaceable Textures.

		unsigned int nRenderFlag; // Render Flags
		unsigned int renderFlagOffset; // Blending modes / render flags.

		unsigned int nBoneLookup; 
		unsigned int boneLookupOffset;//a bone look up table

		unsigned int nTexLookup; //
		unsigned int texLookupOffset; // The same for textures.

		unsigned int nTexUnitLookup;
		unsigned int texUnitLookupOffset; // And texture units. Somewhere they have to be too.

		unsigned int nTranspLookup;
		unsigned int transpLookupOffset; // Everything needs its lookup. Here are the transparencies.

		unsigned int nTexAnimLookup;
		unsigned int texAnimLookupOffset;

		//physics test
		float vertexBox[6];//two points (3 coord per point)
		float vertexRadius;
		float bBox[6];//two points (3 coord per point)
		float bBoxRadius;

		unsigned int bounding_triangles_number;
		unsigned int bounding_triangles_offset;//Our bounding volumes. Similar structure like in the old ofsViews.

		unsigned int bounding_vertices_number; 
		unsigned int bounding_vertices_offset;

		unsigned int bounding_normals_number; 
		unsigned int bounding_normals_offset;

		unsigned int nAttach;
		unsigned int attachOffset; // Attachments are for weapons etc.

		unsigned int nAttachLookup;
		unsigned int attachLookupOffset; // Of course with a lookup.

		unsigned int nEvents; // 
		unsigned int eventsOffset; // Used for playing sounds when dying and a lot else.

		unsigned int nLights; // R
		unsigned int lightsOffset; // Lights are mainly used in loginscreens but in wands and some doodads too.

		unsigned int nCameras;
		unsigned int cameraOffset; // The cameras are present in most models for having a model in the Character-Tab.
		unsigned int nCameraLookup;
		unsigned int cameraLookupOffset; // And lookup-time again.
		
		unsigned int nRibbonEmitters; 
		unsigned int ribbonEmittersOffset; // Things swirling around. See the CoT-entrance for light-trails.

		unsigned int nParticleEmitters;
		unsigned int particleEmittersOffset; // Spells and weapons, doodads and loginscreens use them. Blood dripping of a blade? Particles.
	};

	class M2Vertex
	{
	public:
		float pos[3];
		unsigned char weights[4];
		unsigned char boneIndices[4];
		float normal[3];
		float texcoords[2];
		int unk1, unk2; // always 0,0 so this is probably unused
	};

	class M2TexDef
	{
	public:
		unsigned int type;
		unsigned int flags;
		unsigned int nameLen;
		unsigned int nameOfs;
	};

	class M2RenderFlag
	{
	public:
		unsigned short flags;
		unsigned short blend;
	};

	class M2AnimBlockHeader
	{
	public:
		unsigned int nEntries;
		unsigned int entryOffset;
	};

	class M2AnimBlock
	{
	public:
		short type;		// interpolation type (0=none, 1=linear, 2=hermite)
		short seq;		// global sequence id or -1
		unsigned int nTimes;//number of timelines?
		unsigned int timesOffset;
		unsigned int nKeys;//number of keyframe clips?
		unsigned int keysOffset;
	};

	class M2Animation
	{
	public:
		unsigned short animId;//Animation id in AnimationData.dbc
		unsigned short subAnimId;
		unsigned int length;//The length (timestamps) of the animation in milliseconds.//start at 0 end at length

		float moveSpeed;//This is the speed the character moves with in this animation.

		unsigned int flags;
		unsigned short probability; // This is used to determine how often the animation is played. For all animations of the same type, this adds up to 0x7FFF (32767).
		unsigned short unused;
		unsigned int d1;
		unsigned int d2;
		unsigned int playSpeed;  //Values: 0, 50, 100, 150, 200, 250, 300, 350, 500.

		float boxA[3];//Minimum Extent
		float boxB[3];//MaximumExtent
		float radius;

		short nextAnimIndex;//Id of the following animation of this AnimationID, points to an Index or is -1 if none.
		short index;//Id in the list of animations
	};

	class M2Bone
	{
	public:
		int keyBoneId;
		int flags;
		short parent; // parent bone index,-1 means current bone is root?
		short geoid;
		int unknown; // new int added to the bone definitions.  Added in WoW 2.0
		M2AnimBlock translation;//animations per bone
		M2AnimBlock rotation;
		M2AnimBlock scaling;
		float pivot[3];//Vector3
	};

	class M2Color
	{
	public:
		M2AnimBlock color;
		M2AnimBlock opacity;
	};

	class M2Transp
	{
	public:
		M2AnimBlock trans;
	};

	class M2TexAnim
	{
	public:
		M2AnimBlock translate, rotate, scale;
	};

	class M2FakeAnimBlock
	{
	public:
		unsigned int nTimes;
		unsigned int ofsTimes;
		unsigned int nKeys;
		unsigned int ofsKeys;
	};

	class M2ParticleParams
	{
	public:
		M2FakeAnimBlock colors; 	// (short, vec3f)	This one points to 3 floats defining red, green and blue.
		M2FakeAnimBlock opacity;      // (short, short)		Looks like opacity (short), Most likely they all have 3 timestamps for {start, middle, end}.
		M2FakeAnimBlock sizes; 		// (short, vec2f)	It carries two floats per key. (x and y scale)
		int d[2];
		M2FakeAnimBlock Intensity; 	// Some kind of intensity values seen: 0,16,17,32(if set to different it will have high intensity) (short, short)
		M2FakeAnimBlock unk2; 		// (short, short)
		float unk[3];
		float scales[3];
		float slowdown;
		float unknown1[2];
		float rotation;				//Sprite Rotation
		float unknown2[2];
		float Rot1[3];					//Model Rotation 1
		float Rot2[3];					//Model Rotation 2
		float Trans[3];				//Model Translation
		float f2[4];
		int nUnknownReference;
		int ofsUnknownReferenc;
	};

	class M2ParticleEmitter
	{
	public:
		int id;
		int flags;
		float pos[3]; // The position. Relative to the following bone.
		short bone; // The bone its attached to.
		short texture; // And the texture that is used.
		int nModelFileName;
		int ofsModelFileName;
		int nParticleFileName;
		int ofsParticleFileName; // TODO
		char blend;
		char EmitterType;
		short ParticleColor;
		char ParticleType;
		char HeadorTail;
		short TextureTileRotation;
		short cols;
		short rows;
		M2AnimBlock EmissionSpeed; // All of the following blocks should be floats.
		M2AnimBlock SpeedVariation; // Variation in the flying-speed. (range: 0 to 1)
		M2AnimBlock VerticalRange; // Drifting away vertically. (range: 0 to pi)
		M2AnimBlock HorizontalRange; // They can do it horizontally too! (range: 0 to 2*pi)
		M2AnimBlock Gravity; // Fall down, apple!
		M2AnimBlock Lifespan; // Everyone has to die.
		int unknown;
		M2AnimBlock EmissionRate; // Stread your particles, emitter.
		int unknown2;
		M2AnimBlock EmissionAreaLength; // Well, you can do that in this area.
		M2AnimBlock EmissionAreaWidth;
		M2AnimBlock Gravity2; // A second gravity? Its strong.
		M2ParticleParams p;
		M2AnimBlock en;
	};

	class M2RibbonEmitter
	{
	public:
		int id;
		int bone;
		float pos[3];
		int nTextures;
		int ofsTextures;
		int nUnknown;
		int ofsUnknown;
		M2AnimBlock color;
		M2AnimBlock opacity;
		M2AnimBlock above;
		M2AnimBlock below;
		float res, length, emission_angle;
		short s1, s2;
		M2AnimBlock unk1;
		M2AnimBlock unk2;
		int unknown;
	};

	class M2Camera
	{
	public:
		int id;
		float fov, farclip, nearclip;
		M2AnimBlock transPos;
		float pos[3];//Vector3
		M2AnimBlock transTarget;
		float target[3];//Vector3
		M2AnimBlock rot;
	};

	class M2Light
	{
	public:
		short type;//0 Directional; 1 Point light
		short bone;//If its attached to a bone, this is the bone. Else here is a nice -1.
		float pos[3];//Vector3
		M2AnimBlock ambColor;
		M2AnimBlock ambIntensity;
		M2AnimBlock color;
		M2AnimBlock intensity;
		M2AnimBlock attStart;
		M2AnimBlock attEnd;
		M2AnimBlock unk1;
	};

	class M2SkinHeader
	{
	public:
		char id[4];				 //SKIN
		unsigned int nIndices;
		unsigned int ofsIndices; // Vertices index in this model (index into vertices[])
		unsigned int nTris;//nTris = triangle count *3
		unsigned int ofsTris;	 // the triangles made with them.

		unsigned int nProps, ofsProps; // additional vtx properties
		unsigned int nSub, ofsSub;	 // submeshes
		unsigned int nTex, ofsTex;	 // texture unit
		unsigned int bones	;	//WoW takes this and divides it by the number of bones in each submesh, then stores the biggest one.
	};

	class M2SubMesh
	{
	public:
		unsigned int id;		// mesh part id
		unsigned short vstart;	// first vertex.Starting vertex number.
		unsigned short vcount;	// num vertices
		unsigned short istart;	// first index,Starting triangle index (that's 3* the number of triangles drawn so far).
		unsigned short icount;	// num indices,Number of triangle indices.
		unsigned short nBones;		// number of bone indices, Number of elements in the bone lookup table.
		unsigned short StartBones;		// ? always 1 to 4, Starting index in the bone lookup table.
		unsigned short d5;		// ?
		unsigned short rootBone;		// root bone?
		float BoundingBox[6];
		float radius;
	};//sub mesh entry in .skin file

	/*
	Texture units
	nTextureUnits blocks of 0x18 bytes per record.
	More specifically, textures for each texture unit. 
	Based on the current submesh number, 
	one or two of these are used to determine the texture(s) to bind.
	*/
	class M2TexUnit
	{
	public:
		unsigned short flags;		//Usually 16 for static textures, and 0 for animated textures.	
		unsigned short shading;		// If set to 0x8000: shaders. Used in skyboxes to ditch the need for depth buffering.
		unsigned short geoset_id; // A duplicate entry of a submesh from the list above.
		unsigned short geoset_id_2; // Always same as above?
		short color_index;	// A Color out of the Colors-Block or -1 if none.
		unsigned short flags_index;	// more flags...
		unsigned short texture_unit_id;		//Index into the texture unit lookup table.
		unsigned short mode;			// 
		unsigned short texture_id;	// Texture id (index into global texture list)
		unsigned short texture_unit_id2;	// copy of texture unit value?
		unsigned short transparency_id;		// transparency id (index into transparency list)
		unsigned short texture_anim_id;	// texture animation index into uvanimation lookup table. 
	};

	inline Ogre::Vector3 fixCoord(Ogre::Vector3 v)
	{
		return Ogre::Vector3(v.x, v.z, -v.y);
	}

	inline Ogre::Vector4 fixCoordVec4(Ogre::Vector4 v)
	{
		return Ogre::Vector4(-v.x, -v.z, v.y, v.w);
	}


}

#endif
